package repository

import (
	"gorm.io/gorm"
	"shop-bean/dto"
	"shop-bean/model"
	"shop-common/utils/pagehelper"
	"shop-common/utils/queryWrapper"
)

type IProductRepository interface {
	FindById(db *gorm.DB, id uint) (prod *model.Product, err error)
	FindBySkuId(db *gorm.DB, skuId uint) (*model.Sku, error)
	Create(db *gorm.DB, product *model.Product) error
	CreateBatchSku(db *gorm.DB, skus []*model.Sku) error
	Updates(db *gorm.DB, product *model.Product, columns map[string]interface{}) error
	UpdatesSku(db *gorm.DB, sku *model.Sku, columns map[string]interface{}) error
	FindPage(db *gorm.DB, params *pagehelper.Params) ([]*model.Product, error)
	Count(db *gorm.DB, params *pagehelper.Params) (int64, error)
	Delete(db *gorm.DB, id uint) error
	DeleteSkus(db *gorm.DB, ids []uint) error
	DeleteBySkuId(db *gorm.DB, skuIds []uint) error
	DeleteRelation(db *gorm.DB, dbProduct *model.Product) error
	ReplaceRelation(db *gorm.DB, dbProduct *model.Product, replaceSku []model.Sku) error

	FindByTagIdPage(db *gorm.DB, params *pagehelper.Params, tagId uint) (list []*dto.ProductDTO, err error)
	CountByTagId(db *gorm.DB, params *pagehelper.Params, tagId uint) (count int64, err error)
}

type ProductRepository struct{}

func NewProductRepository() IProductRepository {
	return &ProductRepository{}
}

func (r *ProductRepository) FindById(db *gorm.DB, id uint) (prod *model.Product, err error) {
	return prod, db.Preload("SkuList").Model(&model.Product{}).First(&prod, id).Error
}

func (r *ProductRepository) FindBySkuId(db *gorm.DB, skuId uint) (sku *model.Sku, err error) {
	return sku, db.Model(&model.Sku{}).First(&sku, skuId).Error
}

func (r *ProductRepository) Create(db *gorm.DB, product *model.Product) error {
	return db.Create(&product).Error
}

func (r *ProductRepository) CreateBatchSku(db *gorm.DB, skus []*model.Sku) error {
	return db.Create(&skus).Error
}

func (r *ProductRepository) Updates(db *gorm.DB, product *model.Product, columns map[string]interface{}) error {
	return db.Table(product.TableName()).Where("prod_id = ?", product.ProdId).Updates(columns).Error
}

func (r *ProductRepository) UpdatesSku(db *gorm.DB, sku *model.Sku, columns map[string]interface{}) error {
	db.Model(&model.Sku{}).Unscoped().Where("sku_id = ?", sku.SkuId).Update("deleted_at", gorm.DeletedAt{})
	return db.Model(&model.Sku{}).Unscoped().Where("sku_id = ?", sku.SkuId).Updates(columns).Error
}

func (r *ProductRepository) FindPage(db *gorm.DB, params *pagehelper.Params) (page []*model.Product, err error) {
	tx := queryWrapper.ReuseWherePair(db.Model(&model.Product{}), params.WherePair)
	tx = tx.Scopes(pagehelper.Paginate(params.Current, params.Size))
	return page, queryWrapper.ReuseOrderPair(tx, params.OrderPair).Find(&page).Error
}

func (r *ProductRepository) Count(db *gorm.DB, params *pagehelper.Params) (count int64, err error) {
	tx := queryWrapper.ReuseSelect(db.Model(&model.Product{}), params.SelectFields)
	return count, queryWrapper.ReuseWherePair(tx, params.WherePair).Count(&count).Error
}

func (r *ProductRepository) Delete(db *gorm.DB, id uint) error {
	return db.Delete(&model.Product{}, id).Error
}

func (r *ProductRepository) DeleteSkus(db *gorm.DB, ids []uint) error {
	return db.Delete(&model.Sku{}, ids).Error
}

func (r *ProductRepository) DeleteBySkuId(db *gorm.DB, skuIds []uint) error {
	return db.Delete(&model.Sku{}, skuIds).Error
}

func (r *ProductRepository) DeleteRelation(db *gorm.DB, dbProduct *model.Product) error {
	return db.Model(&model.Product{ProdId: dbProduct.ProdId}).Association("SkuList").Delete(dbProduct.SkuList)
}

func (r *ProductRepository) ReplaceRelation(db *gorm.DB, dbProduct *model.Product, replaceSku []model.Sku) error {
	return db.Model(&model.Product{ProdId: dbProduct.ProdId}).Association("SkuList").Replace(&replaceSku)
}

func (r *ProductRepository) FindByTagIdPage(db *gorm.DB, params *pagehelper.Params, tagId uint) (list []*dto.ProductDTO, err error) {
	return list, selectByTagIdProd(db, params, tagId).Order("p.`updated_at` DESC").Find(&list).Error
}

func (r *ProductRepository) CountByTagId(db *gorm.DB, params *pagehelper.Params, tagId uint) (count int64, err error) {
	return count, selectByTagIdProd(db, params, tagId).Count(&count).Error
}

//todo 多商户还要连接 shop_detail查询
func selectByTagIdProd(db *gorm.DB, params *pagehelper.Params, tagId uint) *gorm.DB {
	tx := db.Table("tz_prod p").
		Select([]string{"p.prod_id", "p.prod_name", "p.price", "p.brief", "p.imgs"}).
		Joins("LEFT JOIN tz_prod_tag_reference ptr ON ptr.`prod_id` = p.`prod_id`").
		Joins("LEFT JOIN tz_prod_tag pt ON pt.`id` = ptr.`tag_id`").
		Where("ptr.`tag_id` = ?", tagId).Where("p.`status` = 2")
	tx = tx.Scopes(pagehelper.Paginate(params.Current, params.Size))
	return tx
}

/*
SELECT
	*
FROM
	tz_prod p
	LEFT JOIN tz_prod_tag_reference ptr ON ptr.`prod_id` = p.`prod_id`
	LEFT JOIN tz_prod_tag pt ON pt.`id` = ptr.`tag_id`
WHERE
	ptr.tag_id = 1
ORDER BY
	p.`updated_at` DESC

*/
